package ru.omsu.diveintoandroid.funnycats.engine;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.cocos2d.layers.CCLayer;
import org.cocos2d.types.CGPoint;
import org.cocos2d.types.CGSize;

//XXX:запутанная логика, много различных типов объектов
//хотя по сути статический объект, это объект с нулевой скоростью
//экстра объект, это объект с огранииченным временнем жизни
//GameWorld должен единолично отвечать за логику перемещения объектов 
public class GameWorld{
	
	//XXX: GameWorld не должен знать про CCLayer
	public GameWorld(CGSize size, CCLayer layer) {
		this.size = size;
		this.layer = layer;
	}

	public void addDynamicObject(GameObject object){
		dynamicObjects.add(object);
		layer.addChild(object.getSprite());
	}
	
	public void addStaticObject(GameObject object){
		staticObjects.add(object);
		layer.addChild(object.getSprite());
	}

	public void addExtraObject(ExtraObject object){
		extraObjects.add(object);
		layer.addChild(object.getSprite());
	}
	
	public void removeDynamicObject(PrototypeObject object){
		dynamicObjects.remove(object);
		layer.removeChild(object.getSprite(), true);
	}
	
	public void removeStaticObject(PrototypeObject object){
		staticObjects.remove(object);
		layer.removeChild(object.getSprite(), true);
	}
	
	public void removeExtraObject(PrototypeObject object){
		extraObjects.remove(object);
		layer.removeChild(object.getSprite(), true);
	}
	
	public List<PrototypeObject> getObjects(){
		List<PrototypeObject> objects = new ArrayList<PrototypeObject>();
		objects.addAll(extraObjects);
		objects.addAll(dynamicObjects);
		objects.addAll(staticObjects);
		return objects;
	}
	
	public List<GameObject> getDynamicObjects(){
		return new ArrayList<GameObject>(dynamicObjects);
	}
	
	private boolean checkNewPosition(GameObject object, CGPoint p){
		if (p.x < 0 || p.x > size.width){
			object.reverseX();
			return true;
		}
		
		if (p.y < 0 || p.y > size.height){
			object.reverseY();
			return true;
		}
		
		return false;
	}
	
	public void step(long dt){
		IsContactWithExtraObject(staticObjects.get(0));
		
		for (GameObject object : dynamicObjects) {
			CGPoint newPosition = object.simulateMove(dt);

			if(!checkNewPosition(object, newPosition)){
				object.move(dt);
			}
			
			if(IsContactWithExtraObject(object)){
				object.setEffect(new Effect());
				object.activateEffect();
			}
						
			if(object.isEffectActive()){
				object.getEffect().tic(dt);
				object.removeEffect();
			}
		}
		
		Collections.reverse(extraObjects);
		
		for (ExtraObject object : extraObjects){
			object.ticTime(dt);
			if(!object.isAlive()){
				layer.removeChild(object.getSprite(),true);
				extraObjects.remove(object);
			}
		}
		
		Collections.reverse(extraObjects);		
	}
	
	public void increaseSpeed(){
		for (GameObject object : dynamicObjects){
			object.increaseSpeed();
		}
	}
	
	//XXX: грубое нарушение code convention, очень сильно режет глаз
	public boolean IsSomeContactExist(GameObject m){
		for(GameObject cat : dynamicObjects){
			if(m.isContactWithOther(cat)) return true;
		}
		
		return false;
	}
	
	//XXX: грубое нарушение code convention, очень сильно режет глаз
	public boolean IsContactWithExtraObject(GameObject mouse){
		for(PrototypeObject extra : extraObjects){
			if(mouse.isContactWithOther(extra)){
				removeExtraObject(extra);
				return true;
			}
		}
		
		return false;
	}
	
	public CGPoint relativePosition(float rx, float ry){
		return CGPoint.ccp(size.width * rx, size.height * ry);
	}
	
	//XXX: грубое нарушение code convention, очень сильно режет глаз
	public boolean IsPointPossible(CGPoint p){
		if ( (p.x > size.width) || (p.x < 0.0f) ) return false;
		if ( (p.y > size.height)|| (p.y < 0.0f) ) return false;

		return true;
	}
	
	//XXX: грубое нарушение code convention, очень сильно режет глаз
	public CGPoint MakeNearestPossiblePoint(CGPoint p){
		if (p.x > size.width) p.x = size.width;
		if (p.y > size.height) p.y = size.height;
		if (p.x < 0.0f) p.x = 0.0f;
		if (p.y < 0.0f) p.y = 0.0f;
		
		return p;
	}
	
	//XXX: грубое нарушение code convention, очень сильно режет глаз
	public boolean isPossibleAddExtraObjects(){
		return extraObjects.size() < MAX_NUM_OF_EXTRA_OBJECTS;
	}
	
	private CGSize size;
	private int MAX_NUM_OF_EXTRA_OBJECTS = 2;
	private List<GameObject> dynamicObjects	= new ArrayList<GameObject>();
	private List<GameObject> staticObjects	= new ArrayList<GameObject>();
	private List<ExtraObject> extraObjects	= new ArrayList<ExtraObject>();
	private CCLayer layer;
}